
/*
* Copyright 2010, Center for Advanced Information Systems,Nanyang Technological University
*
* File name: BuildQuery.java
*
* Abstract: Build the Query Graph
*
* Current Version:      0.1
* Auther:               Jin Changjiu
* Modified Date:        Jun.3,2010
*
*/
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gblend.exactquery;


import java.sql.SQLException;
import gblend.frequentindex.Vertex;
import gblend.infrequentindex.BuildCam;
import gblend.modification.Modification;
import gblend.result.InfoChart;
import gblend.result.Record;
import java.util.Iterator;
import java.util.Vector;
import gblend.similarity.SimilarQuery;
import gblend.util.QueryEdge;
import javax.swing.JFrame;
//import javax.swing.JOptionPane;


/**
 *
 * @author cjjin
 */
public class BuildQuery extends JFrame{

    private int edgenum = 0;
    private SNode wholeQuery = null;
    private int qnnum = 0;
    private long starttime;
    private long formtime;

    private Vector<QueryNodeID> qn = new Vector<QueryNodeID>(); //store all the query nodes
    private QueryEngine qengine = new QueryEngine();
    private SimilarQuery sq = new SimilarQuery();
    //Whether it is exact or similar search
    //private boolean status = false;
    private SNode seed = null;//the newest edge
    private Vector<QueryEdge> edgetable = new Vector<QueryEdge>();
  //  private BuildCam bc = new BuildCam();
    private Modification md = new Modification();

    private Vector<Record> stepRecord = new Vector<Record>();
    private InfoChart chart = null;
  
 //record the nodes added on the Query panel
  public void recordNodes(int hashcode,String nodelabel)
  {
        /*String[] reallabels = qengine.getDBcon().getLabels();
        String labelid = "";
        for(int i=0;i<reallabels.length;i++)
        {
            if(reallabels[i].equals(nodelabel))
            {
                labelid = ""+i;
                break;
            }
        }*/
      System.out.println("nodelabel = "+nodelabel);
  
        QueryNodeID tmpqn = new QueryNodeID();
        tmpqn.setHashcode(hashcode);
        tmpqn.setNodelabel(nodelabel);
        tmpqn.setid(qnnum);//start from 0

        qn.addElement(tmpqn);
        qnnum++;
        if(qnnum==1)
        {//start timing once the first node is added
            starttime = System.currentTimeMillis();
        }

  }


 /*
 *  record the edges added on the panel
 */
  public int recordEdge(int source, int target) throws SQLException, ClassNotFoundException
  {
      System.out.println(">>> BuildQuery.recordEdge");
      int suggestedEdge = 0;
      int exactSize = 0;
      int simSize = 0;
      QueryEdge qedge = new QueryEdge();
      
      Iterator  iter = qn.iterator();
      while(iter.hasNext())
      {
         QueryNodeID tqn = (QueryNodeID) iter.next();
         if(tqn.getHashcode()==source)
         {
             qedge.setSrc(tqn.getid());
         }
         else if(tqn.getHashcode()==target)
         {
              qedge.setTrg(tqn.getid());
         }
      }

      qedge.setId(edgenum++);
      edgetable.addElement(qedge);

      System.out.println("\nEdge: "+edgenum);
      formtime=(System.currentTimeMillis()-starttime)/1000;//the time used to formulate the whole query

      constructSeed();//construct the new edge as a seed graph
      formQuery(); // construct the query

      long time1=0, time2=0;
      time1 = System.currentTimeMillis();
      boolean status=true;
   exactSize =qengine.executeQuery(this, 0, status);//invoke the exact query and spindlegraph building
   //   time2 = System.currentTimeMillis();
    
      // this OptionDialogue only appears once
   /*   if(status == true && qengine.getQuerytype()==3)
      {
          String   message = "Current query has no exact Results";
          Object[] options = {"Modify the Query", "Similarity Search"};
          int n = JOptionPane.showOptionDialog(this,
          message, "Query Options",
          JOptionPane.YES_NO_OPTION,
          JOptionPane.QUESTION_MESSAGE,
          null, options, options[0]);

          if(n == 0)
          {
              suggestedEdge = md.modifySuggestion(qengine); //compute the modification suggestion
          }
          else if(n == 1)
          {
               status = false;//invoke the similarity search
          }
     }*/
        
    // if(status == false)//start the similarity search
    // {
     //       time1 = System.currentTimeMillis();
            simSize = sq.simCandidateCalculate(wholeQuery, qengine);
            time2 = System.currentTimeMillis();
  //   }
     
     float finaltime  = (float)(time2 - time1);
     Record r = new Record();
     r.insertRecord(finaltime, exactSize, simSize);
     stepRecord.addElement(r);
     System.out.println("Query Precomputing time(ms): "+finaltime);
     
     chart.set(stepRecord);
     chart.repaint();
     chart.setVisible(true);
     
     return suggestedEdge;
 }

 public void modifyQuery(int hashcode, int edgeid) throws SQLException, ClassNotFoundException
 {
     int exactSize = 0;
      int simSize = 0;
     edgenum--;//edege number -1
   
    QueryNodeID qnode = null;
    if(hashcode!=0)//if a node is deleted with the edge
    {
       
        for(Iterator itr = qn.iterator();itr.hasNext();)
        {
            qnode = (QueryNodeID)itr.next();
            if(qnode.getHashcode()==hashcode)
            {
                itr.remove();
                qnnum--;
                break;
            }
        }
        //modify the node ids of the rest nodes
       for(Iterator itr = qn.iterator();itr.hasNext();)
       {
            QueryNodeID qnode2 = (QueryNodeID)itr.next();
            if(qnode2.getid()>qnode.getid())
            {
                qnode2.setid(qnode2.getid()-1);
            }
       }
      
    }


    for(Iterator itr = edgetable.iterator();itr.hasNext();)
    {
          QueryEdge qedge = (QueryEdge)itr.next();
         if(qedge.getId()==edgeid)//remove the deleted edge from edgetable
         {
             itr.remove();
         }
         else if(qedge.getId()>edgeid)//8.28 modify the edge ids of the rest edges
         {
            qedge.setId(qedge.getId()-1);
         }

         if(qnode!=null)//modify the srcid and trgid of edge
         {
             if(qedge.getSrc()>qnode.getid())
            {
                qedge.setSrc(qedge.getSrc()-1);
            }

            if(qedge.getTrg()>qnode.getid())
            {
                qedge.setTrg(qedge.getTrg()-1);
            }
         }
    }

     long time1 = System.currentTimeMillis();
     formQuery(); // reconstruct the new query
    //modification based on spindleshaped graph
     md.queryModification(qengine, edgeid+1, edgenum);//edgeid starts from 0
    
     //even though status = false, after modification, it could become an exact query.
     exactSize = qengine.executeQuery(this, edgeid+1, true);//first check if it is exact query after modification
   /*  if(exactSize != 0)
     {
        status = true;
     }

     if(status == false)//modification in similarity query
     {*/
       simSize = sq.simCandidateCalculate(wholeQuery, qengine);
  //   }
    
   long time2 = System.currentTimeMillis();
   float finaltime  = (float)(time2 - time1);

   Record r = new Record();
   r.insertRecord(finaltime, exactSize, simSize);
   stepRecord.addElement(r);
   System.out.println("Query Modification time(ms): "+finaltime);
   chart.set(stepRecord);
   chart.repaint();
   chart.setVisible(true);

 }

 
 //formulate the new query graph
  public void formQuery()
  {
      System.out.println(">>> BuildQuery.formQuery");
      //copy the previous node
       wholeQuery = new SNode(qnnum);
       wholeQuery.setNnum(qnnum);

       for(int i = 0; i < qnnum;i++)
       {
            Vertex v = new Vertex();
            QueryNodeID tmpnode = qn.elementAt(i);
            v.setLabel(tmpnode.getNodelable());
            v.setId(i);
            v.setQId(i);
            wholeQuery.addnode(v);
       }
      
       for(int i = 0; i< edgetable.size();i++)
       {
          QueryEdge tmpedge = edgetable.elementAt(i);
          int f = tmpedge.getSrc();
          int t = tmpedge.getTrg();
          wholeQuery.addEdge(f, t, tmpedge.getId()+1);//edge label starts from 1
          wholeQuery.getNode(f).setDegree();
          wholeQuery.getNode(t).setDegree();
          wholeQuery.getNode(f).setIn(t);
          wholeQuery.getNode(t).setIn(f);
         
       }
   
       wholeQuery.setEnum(edgenum);
       String cam = BuildCam.buildCam(wholeQuery);
       wholeQuery.setCam(cam);
      
 }

//construct the new edge as the seed of SPIG
  public void constructSeed()
  {
      System.out.println(">>> BuildQuery.constructSeed");
    seed = new SNode(2);
    Vertex v1 = new Vertex();
    int qid1 = edgetable.lastElement().getSrc();
    QueryNodeID tmpnode1 = qn.elementAt(qid1);
    String label1 = tmpnode1.getNodelable();
    v1.setLabel(label1);
    v1.setQId(qid1);//node in seed attached the id in query
    v1.setId(0);
    seed.addnode(v1);

    Vertex v2 = new Vertex();
    int qid2 = edgetable.lastElement().getTrg();
    QueryNodeID tmpnode2 = qn.elementAt(qid2);
    String label2 = tmpnode2.getNodelable();
    v2.setLabel(label2);
    v2.setQId(qid2);
    v2.setId(1);
    seed.addnode(v2);

    seed.addEdge(0, 1, edgenum);//set label on the edge
    seed.getNode(0).setDegree();
    seed.getNode(1).setDegree();
    seed.setIdinQuery(qid1);
    seed.setIdinQuery(qid2);

    seed.setEnum(1);
    seed.setNnum(2);
    seed.setGraphid(0);

    seed.setEdgelabeSet(edgenum);
   int label1i = Integer.parseInt(label1);
   int label2i = Integer.parseInt(label2);
    if(label1i>=label2i)
    {
        seed.setCam("("+label1+")1("+label2+")");
    }
    else
    {
        seed.setCam("("+label2+")1("+label1+")");
    }

  }

  
  public SNode getWholeQuery()
  {
     return wholeQuery;
  }

  public QueryEngine getQueryMatch()
  {
      System.out.println(">>> BuildQuery.getQueryMatch");
     return qengine;
  }

  public long getformulationtime()
  {
      return formtime;
  }


 public SimilarQuery getSQ()
 {
     System.out.println(">>> BuildQuery.getSQ");
    return sq;
 }

//return the newest edge
 public SNode getSeed()
 {
    return seed;
 }
 public void setFrame(InfoChart frame)
 {
    chart=frame;
 }

}
